/*
 * Copyright 2009 BioTeam Inc
 * 
 * Licensed under License GNU LESSER GENERAL PUBLIC LICENSE version 3.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.bioteam.appweb.gwt.apps.server;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.zip.ZipOutputStream;

import javax.activation.MimeType;
import javax.activation.MimeTypeParseException;
import javax.persistence.EntityManager;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.bioteam.appweb.gwt.apps.clientandserver.Constant;
import net.bioteam.appweb.gwt.apps.clientandserver.ServerException;
import net.bioteam.cloud.cluster.ActiveCluster;
import net.bioteam.cloud.cluster.Cluster;
import net.bioteam.common.user.User;
import net.bioteam.common.utils.MyEntityManager;
import net.bioteam.common.utils.Utils;

import org.apache.commons.fileupload.util.Streams;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ContentServlet extends HttpServlet
{
	public static final Log logger = LogFactory.getLog(ContentServlet.class);
	/**
     *
     */
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
	{
		String path = req.getPathInfo();
		if (req.getSession(false) == null)
		{
			resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
			return;
		}
		if (req.getSession(false).getAttribute("username") == null)
		{
			resp.sendError(HttpServletResponse.SC_UNAUTHORIZED);
			return;
		}
		String username = (String) req.getSession(false).getAttribute("username");
		User user = (User) req.getSession(false).getAttribute("user");
		String zip = (String) req.getParameter("zip");
		String pdf = (String) req.getParameter("pdf");
		if (path.startsWith(Constant.clusterPrefix))
		{
			long id=Long.parseLong(path.substring(Constant.clusterPrefix.length()));
			//User user = (User) getThreadLocalRequest().getSession().getAttribute("user");
			EntityManager em = MyEntityManager.getEntityManager();
			Cluster cluster = em.find(Cluster.class, id);
			if (cluster==null)
			{
				logger.warn(path+" is not found");
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			if (!cluster.getUserid().equals(user.getIdAsString()))
			{
				logger.warn(path+" is not permitted");
				resp.sendError(HttpServletResponse.SC_FORBIDDEN);
				return;
			}
			String key= cluster.getKeyMaterial();
			resp.setContentLength(key.length());
			resp.setContentType("text/plain");
			resp.getWriter().write(key);
			resp.getWriter().close();
			return;
		}
		if (zip == null)
		{
			File file;
			try
			{
				file = new File(UserFileConverter.clientPathToRealPath(path, username));
			} catch (UnsupportedUserFileTypeException e)
			{
				logger.warn(e.getMessage());
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			String pdfName = null;
			if (pdf != null)
			{
				String tempName = file.getAbsolutePath();
				pdfName = tempName;
				tempName = tempName.substring(0, tempName.length() - 4) + ".ps";
				file = new File(tempName);
			}
			if (!file.exists())
			{
				logger.warn("client request content non existent file " + file.getAbsolutePath());
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}

			if (pdf != null)
			{
				String error = ps2Pdf(file, pdfName);
				if (error != null)
				{
					// logger.warn("client request content non existent file "+file.getAbsolutePath());
					resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, error);
					return;
				}
				file = new File(pdfName);
			}
			long size = file.length();

			resp.setContentLength((int) size);
			resp.setContentType(getType(file.getName()));

			BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));
			ServletOutputStream out = resp.getOutputStream();
			IOUtils.copy(in, out);
			out.close();
			in.close();
		} else
		{
			// remove ".zip suffix";
			path = path.substring(0, path.length() - 4);

			File file;
			try
			{
				file = new File(UserFileConverter.clientPathToRealPath(path, username));
			} catch (UnsupportedUserFileTypeException e)
			{
				logger.warn(e.getMessage());
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			if (!file.exists())
			{
				logger.warn("client request content non existent file " + file.getAbsolutePath());
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}
			if (file.isFile())
			{
				logger.warn("request zip file is not a directory " + file.getAbsolutePath());
				resp.sendError(HttpServletResponse.SC_NOT_FOUND);
				return;
			}

			resp.setContentType("application/zip");
			ZipOutputStream out = new ZipOutputStream(resp.getOutputStream());
			Utils.zipDir(out, file, null);
			out.close();
		}
	}

	private String getType(String fileName)
	{

		String ext = FilenameUtils.getExtension(fileName);
		MimeType type = null;

		try
		{
			type = new MimeType("text", "plain");
		} catch (MimeTypeParseException e1)
		{
			// ignore
		}

		if (ext != null && ext.length() > 0)
		{
			try
			{
				String mtype = MimeTypes.getType(ext);

				if (mtype != null)
				{
					type = new MimeType(mtype);
				}
			} catch (MimeTypeParseException e)
			{
				// ignore.
			}
		}

		return type.toString();
	}

	private String ps2Pdf(File from, String to)
	{
		ProcessBuilder pb = new ProcessBuilder("/usr/bin/ps2pdf", from.getAbsolutePath(), to);
		// Map<String, String> env = pb.environment();
		// env.put("VAR1", "myValue");
		// env.remove("OTHERVAR");
		// env.put("VAR2", env.get("VAR1") + "suffix");
		try
		{
			pb.directory(from.getParentFile());
			Process p = pb.start();
			p.waitFor();
			if (p.exitValue() != 0)
			{
				return Streams.asString(p.getErrorStream());
			} else
			{
				return null;
			}
		} catch (Exception e)
		{
			return e.getMessage();
		}
	}
}
